﻿using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Framework
{
    public class UILayerManager : MonoSingleton<UILayerManager>
    {
//        public const float UI_WIDTH = 1280f;
//        public const float UI_HEIGHT = 960f;
        
        private GameObject _gameObject;
        private RectTransform _transform;
        private Canvas _canvas;
        private UILayer[] _listUILayer;

        private GameObject _goEventSystem;
        private EventSystem _eventSystem;
        private CanvasScaler _scaler;
        private Camera _camera;
        private UIFillLayer _fillLayer;
        private float _width;
        private float _height;
        private float _preferWidth;
        private float _minHeight;
        private float _maxHeight;

        public Camera camera
        {
            get { return _camera; }
        }

        public float width
        {
            get { return _width; }
        }

        public float height
        {
            get { return _height; }
        }
        
        public override void Awake()
        {
            base.Awake();
            InitCamera();
            InitCanvas();
            InitEventSystem();
            InitLayers();
            InitFillLayer();
        }

        public void SetPreferResolution(float preferWidth, float minAspect, float maxAspect)
        {
            _preferWidth = preferWidth;
            float sourceAspect = _camera.aspect;
            _maxHeight = preferWidth / minAspect;
            _minHeight = preferWidth / maxAspect;
            float width = preferWidth;
            float height = preferWidth / sourceAspect;
            float matchWidthOrHeight = 0f;
            if (height < _minHeight)
            {
                height = _minHeight;
                matchWidthOrHeight = 1f;
                width = height * sourceAspect;
                SetFillWidth(width - preferWidth, width);
            }
            else if (height > _maxHeight)
            {
                SetFillHeight(height - _maxHeight, height);
            }
            _scaler.referenceResolution = new Vector2(width, height);
            _scaler.matchWidthOrHeight = matchWidthOrHeight;
            _width = width;
            _height = height;
        }

        public UILayer GetLayer(int name)
        {
            return _listUILayer[name];
        }

        public Canvas GetCanvas()
        {
            return _canvas;
        }

        public void SetCanvasToPreferResolution(Canvas canvas)
        {
            float sourceAspect = _camera.aspect;
            float height = _preferWidth / sourceAspect;
            
            CanvasScaler scaler = canvas.GetComponent<CanvasScaler>();
            RectTransform rectTransform = canvas.transform.Find("Container") as RectTransform;
            if (height < _minHeight)
            {
                float halfPercent = 0.5f * (_width - _preferWidth) / _width;
                Vector2 anchorMin = Global.Vec2;
                anchorMin.x = halfPercent;
                anchorMin.y = 0;
                rectTransform.anchorMin = anchorMin;
                Vector2 anchorMax = Global.Vec2;
                anchorMax.x = 1f - halfPercent;
                anchorMax.y = 1f;
                rectTransform.anchorMax = anchorMax;
            }
            else if (height > _maxHeight)
            {
                float halfPercent = 0.5f * (_height - _maxHeight) / _height;
                Vector2 anchorMin = Global.Vec2;
                anchorMin.x = 0;
                anchorMin.y = halfPercent;
                rectTransform.anchorMin = anchorMin;
                Vector2 anchorMax = Global.Vec2;
                anchorMax.x = 1f;
                anchorMax.y = 1f - halfPercent;
                rectTransform.anchorMax = anchorMax;
            }
            scaler.referenceResolution = new Vector2(width, height);
            scaler.matchWidthOrHeight = _scaler.matchWidthOrHeight;
        }

        private void InitCamera()
        {
            GameObject goGamera = new GameObject("UICamera", typeof(Camera));
            goGamera.transform.position = new Vector3(-1000f, -1000f, -1000f);
            _camera = Camera.main;
            _camera.clearFlags = CameraClearFlags.Color;
            _camera.backgroundColor = Color.black;
            _camera.cullingMask = Layer.UIMask;
            _camera.farClipPlane = 100f;
            _camera.depth = 0;
            _camera.orthographic = true;
        }
        
        private void InitCanvas()
        {
            _gameObject = new GameObject("Canvas", typeof(RectTransform));
            _gameObject.layer = Layer.UI;
            _transform = _gameObject.transform as RectTransform;
            _canvas = _gameObject.AddComponent<Canvas>();
            _canvas.renderMode = RenderMode.ScreenSpaceCamera;
            _canvas.worldCamera = _camera;
            _canvas.sortingLayerID = SortingLayer.NameToID("UI");
            _scaler = _gameObject.AddComponent<CanvasScaler>();
            _scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
            _scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
            _gameObject.AddComponent<GraphicRaycaster>();
        }

        private void InitEventSystem()
        {
            _goEventSystem = new GameObject("EventSystem");
            _goEventSystem.AddComponent<StandaloneInputModule>();
            _eventSystem = _goEventSystem.GetComponent<EventSystem>();
        }

        private void InitLayers()
        {
            int[] allName = UILayerName.AllName;
            _listUILayer = new UILayer[allName.Length];
            foreach (int name in allName)
            {
                UILayer uiLayer = UILayerFcatory.CreateUILayer(name, _transform);
                _listUILayer[name] = uiLayer;
            }
        }

        private void InitFillLayer()
        {
            _fillLayer = new UIFillLayer("Fill", _transform);
        }

        private void SetFillWidth(float fillWidth, float width)
        {
            _fillLayer.SetFillWidth(fillWidth, width);
            int count = _listUILayer.Length;
            for (int i = 0; i < count; ++i)
            {
                _listUILayer[i].SetFillWidth(fillWidth, width);
            }
        }

        private void SetFillHeight(float fillHeight, float height)
        {
            _fillLayer.SetFillHeight(fillHeight, height);
            int count = _listUILayer.Length;
            for (int i = 0; i < count; ++i)
            {
                _listUILayer[i].SetFillHeight(fillHeight, height);
            }
        }
    }
}